package com.koi.system.controller.user;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.koi.common.anno.KoiLog;
import com.koi.common.constants.KoiConstants;
import com.koi.common.enums.log.OperType;
import com.koi.common.ex.koi.YUtil;
import com.koi.common.satoken.KoiLoginUtil;
import com.koi.common.satoken.KoiPasswordUtil;
import com.koi.common.utils.file.FileTypeUtil;
import com.koi.common.utils.number.VerifyCodeUtil;
import com.koi.easyexcel.core.utils.EasyExcelUtil;
import com.koi.model.vo.system.SysLoginUserVo;
import com.koi.model.vo.system.SysPwdVo;
import com.koi.pojo.system.SysLoginUser;
import com.koi.system.service.post.SysPostService;
import com.koi.system.service.role.SysRoleService;
import com.koi.system.service.user.SysLoginUserService;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;

/**
 * @author ･ᴗ･
 * @description [用户信息表-控制层]
 */
@Validated
@RequestMapping("/koi")
@RequiredArgsConstructor
@RestController
public class SysLoginUserController {

    private final EasyExcelUtil easyExcelUtil;

    private final SysLoginUserService sysLoginUserService;

    private final SysPostService sysPostService;

    private final SysRoleService sysRoleService;


    /**
     * @description [分页查询]
     * @author ･ᴗ･
     */
    @SaCheckPermission("system:user:list")
    @GetMapping("/sysLoginUser/listPage")
    public IPage<SysLoginUser> listPage(SysLoginUserVo vo) {
        return sysLoginUserService.listPage(vo);
    }

    /**
     * @description [查询所有]
     * @author ･ᴗ･
     */
    @GetMapping("/sysLoginUser/list")
    public List<SysLoginUser> list() {
        return sysLoginUserService.list();
    }

    /**
     * @description [查询一个]
     * @author ･ᴗ･
     */
    @GetMapping("/sysLoginUser/getById/{id}")
    public SysLoginUser getById(@PathVariable("id") Long id) {
        // 条件构造器
        LambdaQueryWrapper<SysLoginUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(null != id, SysLoginUser::getUserId, id);
        wrapper.select(SysLoginUser.class,
                column -> !column.getColumn().equals("password")
                        && !column.getColumn().equals("salt")
                        && !column.getColumn().equals("login_ip")
                        && !column.getColumn().equals("login_time")
                        && !column.getColumn().equals("pwd_update_time")
                        && !column.getColumn().equals("create_by")
                        && !column.getColumn().equals("update_by")
                        && !column.getColumn().equals("update_time")
        );
        SysLoginUser loginUser = sysLoginUserService.getOne(wrapper);
        loginUser.setPostIds(sysPostService.listRightPost(id));
        loginUser.setRoleIds(sysRoleService.listRightRole(id));
        return loginUser;
    }

    /**
     * @description [新增]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户新增", operType = OperType.ADD)
    @SaCheckPermission("system:user:add")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/add")
    public void add(@Validated @RequestBody SysLoginUser sysLoginUser) {
        // 1、先查询是否已经存在登录名
        LambdaQueryWrapper<SysLoginUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysLoginUser::getLoginName, sysLoginUser.getLoginName());
        long count = sysLoginUserService.count(wrapper);
        YUtil.isTrue(count > 0, "该登录名已存在，请重新输入");
        // 2、设置盐值和密码
        sysLoginUser.setSalt(VerifyCodeUtil.generateMixedLetters(6));
        sysLoginUser.setPassword(KoiPasswordUtil.getPassword(sysLoginUser.getPassword(), sysLoginUser.getSalt()));
        if (StringUtils.isNotBlank(KoiLoginUtil.getUserName())) {
            sysLoginUser.setCreateBy(KoiLoginUtil.getUserName());
        }
        YUtil.isTrue(!sysLoginUserService.save(sysLoginUser), "新增失败，请稍后重试");
        SysLoginUser loginUser = sysLoginUserService.getOne(wrapper);
        // 3、添加岗位和角色
        sysPostService.assignUserPost(loginUser.getUserId(), sysLoginUser.getPostIds());
        sysRoleService.assignUserRole(loginUser.getUserId(), sysLoginUser.getRoleIds());
    }

    /**
     * @description [修改]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户修改", operType = OperType.UPDATE)
    @SaCheckPermission("system:user:update")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/update")
    public void update(@Validated @RequestBody SysLoginUser sysLoginUser) {
        // 1、修改用户基本信息
        if (StringUtils.isNotBlank(KoiLoginUtil.getUserName())) {
            sysLoginUser.setUpdateBy(KoiLoginUtil.getUserName());
        }
        YUtil.isTrue(!sysLoginUserService.updateById(sysLoginUser), "修改失败，请稍后重试");
        // 2、添加岗位和角色
        sysPostService.assignUserPost(sysLoginUser.getUserId(), sysLoginUser.getPostIds());
        sysRoleService.assignUserRole(sysLoginUser.getUserId(), sysLoginUser.getRoleIds());
    }

    /**
     * @description [删除]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户删除", operType = OperType.DELETE)
    @SaCheckPermission("system:user:delete")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/deleteById/{id}")
    public void delete(@PathVariable("id") Long id) {
        // 1、超级管理员不可删除
        YUtil.isTrue(id == 1L, "超级管理员不可删除");
        // 2、删除用户数据
        YUtil.isTrue(!sysLoginUserService.removeById(id), "删除失败，请稍后重试");
        // 3、删除当前用户拥有的岗位
        sysPostService.deleteUserPost(id);
        // 4、删除当前用户拥有的角色
        sysRoleService.deleteUserRole(id);
    }

    /**
     * @description [批量删除]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户批量删除", operType = OperType.DELETE)
    @SaCheckPermission("system:user:delete")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/batchDelete")
    public void deleteBatch(@NotNull(message = "请选择需要删除的数据") @RequestBody List<Long> ids) {
        for (Long id : ids) {
            // 1、超级管理员不可删除
            YUtil.isTrue(id == 1L, "超级管理员不可删除");
            // 2、删除当前用户拥有的岗位
            sysPostService.deleteUserPost(id);
            // 3、删除当前用户拥有的角色
            sysRoleService.deleteUserRole(id);
        }
        // 4、删除用户
        YUtil.isTrue(!sysLoginUserService.removeBatchByIds(ids), "删除失败，请稍后重试");
    }

    /**
     * @description [修改状态]
     * @author ･ᴗ･
     */
    @PostMapping("/sysLoginUser/updateStatus/{userId}/{userStatus}")
    public void update(@PathVariable("userId") Long userId, @PathVariable("userStatus") String userStatus) {
        UpdateWrapper<SysLoginUser> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("user_status", userStatus).eq("user_id", userId);
        YUtil.isTrue(!sysLoginUserService.update(null, updateWrapper), "修改失败，请稍后重试");
    }

    /**
     * @description [获取登录用户信息、角色、左侧菜单栏(另外一个接口)、按钮等权限]
     * @author ･ᴗ･
     */
    @GetMapping("/sysLoginUser/getLoginUserInformation")
    public Map<String, Object> getLoginUserInformation() {
        return sysLoginUserService.getLoginUserInformation();
    }

    /**
     * @description [个人中心-左侧卡片资料数据]
     * @author ･ᴗ･
     */
    @GetMapping("/sysLoginUser/getPersonalData")
    public Map<String, Object> getPersonalData() {
        return sysLoginUserService.getPersonalData();
    }

    /**
     * @description [个人中心-修改基本资料 和 头像]
     * @author ･ᴗ･
     */
    @PostMapping("/sysLoginUser/updateBasicData")
    public void updateBasicData(@RequestBody SysLoginUser sysLoginUser) {
        sysLoginUser.setUserId(KoiLoginUtil.getUserId());
        YUtil.isTrue(!sysLoginUserService.updateById(sysLoginUser), "操作失败");
    }

    /**
     * @description [修改密码]
     * @author ･ᴗ･
     */
    @KoiLog(title = "修改密码", operType = OperType.UPDATE)
    @PostMapping("/sysLoginUser/updateUserPwd")
    public void updateUserPwd(@Validated @RequestBody SysPwdVo vo) {
        SysLoginUser sysLoginUser = sysLoginUserService.getById(KoiLoginUtil.getUserId());
        YUtil.isTrue(ObjectUtils.isEmpty(sysLoginUser), "用户信息发生改变，请重新登录");
        // 1、输入的密码是否和数据库密码一致
        String password = vo.getPassword();
        String inputPwd = KoiPasswordUtil.getPassword(password, sysLoginUser.getSalt());
        String databasePwd = sysLoginUser.getPassword();
        YUtil.isTrue(!inputPwd.equals(databasePwd), "密码输入错误");
        // 2、密码是否和新密码一致
        String newPassword = vo.getNewPassword();
        YUtil.isTrue(password.equals(newPassword), "新密码不能与旧密码相同");
        // 3、新密码是否和确认密码一致
        String confirmPassword = vo.getConfirmPassword();
        YUtil.isTrue(!newPassword.equals(confirmPassword), "新密码与确认密码不一致");
        // 4、保存新密码至数据库中
        String finshPwd = KoiPasswordUtil.getPassword(newPassword, sysLoginUser.getSalt());
        LambdaUpdateWrapper<SysLoginUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(SysLoginUser::getPassword, finshPwd);
        updateWrapper.set(SysLoginUser::getPwdUpdateTime, new Date());
        updateWrapper.eq(SysLoginUser::getUserId, KoiLoginUtil.getUserId());
        YUtil.isTrue(!sysLoginUserService.update(updateWrapper), "修改失败，请稍后重试");
    }

    /**
     * 在@PathVariable上使用@NotBlank或@NotNull时，这些验证注解实际上不会生效
     * @description [重置密码]
     * @author ･ᴗ･
     */
    @KoiLog(title = "重置密码", operType = OperType.UPDATE)
    @SaCheckPermission("system:user:resetPwd")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/resetPwd/{id}/{password}")
    public void resetPwd(@PathVariable("id") Long id, @PathVariable("password") String password) {
        // 1、参数校验
        YUtil.isTrue(id == null, "用户ID不能为空");
        YUtil.isNull(password, "用户密码不能为空");
        YUtil.isTrue(password.length() < 6, "密码长度不能小于6位");
        SysLoginUser sysLoginUser = sysLoginUserService.getById(id);
        YUtil.isTrue(ObjectUtils.isEmpty(sysLoginUser), "用户信息发生改变，请重新登录");
        // 2、密码加密
        String encryptPwd = KoiPasswordUtil.getPassword(password, sysLoginUser.getSalt());
        // 3、修改密码
        LambdaUpdateWrapper<SysLoginUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(SysLoginUser::getPassword, encryptPwd);
        updateWrapper.set(SysLoginUser::getPwdUpdateTime, new Date());
        updateWrapper.eq(SysLoginUser::getUserId, id);
        boolean update = sysLoginUserService.update(updateWrapper);
        YUtil.isTrue(!update, "重置密码失败，请重试");
    }

    /**
     * @description [用户下载模版]
     * @author ･ᴗ･
     */
    @GetMapping("/sysLoginUser/downloadExcelTemplate")
    public void downloadExcelTemplate(HttpServletResponse response) {
        try {
            List<SysLoginUser> list = new ArrayList<>();
            easyExcelUtil.exportExcel(response, list, SysLoginUser.class, "下载模版", "下载模版");
        } catch (Exception e) {
            YUtil.isTrue("模版生成失败");
        }
    }

    /**
     * @description [多条件用户数据导出]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户数据导出", operType = OperType.EXPORT)
    @SaCheckPermission("system:user:export")
    @GetMapping("/sysLoginUser/exportExcelData")
    public void exportExcelData(SysLoginUserVo vo, HttpServletResponse response) {
        try {
            List<SysLoginUser> list = sysLoginUserService.listLoginUser(vo);
            easyExcelUtil.exportExcel(response, list, SysLoginUser.class, "导出", "用户信息表");
        } catch (Exception e) {
            YUtil.isTrue("导出失败");
        }
    }

    /**
     * @description [用户数据导入]
     * @author ･ᴗ･
     */
    @KoiLog(title = "用户数据导出", operType = OperType.IMPORT)
    @SaCheckPermission("system:user:import")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/sysLoginUser/importExcelData")
    public void importExcelData(@RequestParam("file") MultipartFile multipartFile) {
        try {
            // 判断是否符合excel文件格式
            FileTypeUtil.decideIsExcel(multipartFile);
            // 导入数据的字段类型和实体类要保持一致
            List<SysLoginUser> list = easyExcelUtil.importExcel(multipartFile, SysLoginUser.class, null);
            if (CollectionUtils.isNotEmpty(list)) {
                System.out.println("本次成功导入：" + list.size() + "条");
                List<SysLoginUser> importList = new ArrayList<>();
                list.forEach(yu -> {
                    SysLoginUser sysLoginUser = new SysLoginUser();
                    sysLoginUser.setLoginName(yu.getLoginName());
                    sysLoginUser.setUserName(yu.getUserName());
                    sysLoginUser.setSalt(VerifyCodeUtil.generateMixedLetters(6));
                    sysLoginUser.setPassword(KoiPasswordUtil.getPassword(sysLoginUser.getSalt(), "123456"));
                    sysLoginUser.setUserType(KoiConstants.TWO_STRING);
                    sysLoginUser.setEmail(yu.getEmail());
                    sysLoginUser.setPhone(yu.getPhone());
                    sysLoginUser.setSex(yu.getSex());
                    sysLoginUser.setAvatar(yu.getAvatar());
                    sysLoginUser.setUserStatus(KoiConstants.ZERO_STRING);
                    sysLoginUser.setCreateTime(new Date());
                    importList.add(sysLoginUser);
                });
                boolean saveBatch = sysLoginUserService.saveBatch(importList);
                YUtil.isTrue(!saveBatch, "导入失败");
            }
        } catch (Exception e) {
            YUtil.isTrue("导入失败");
        }
    }

}
